package com.dengdai.videoplay;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.media.AudioManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Manage MediaPlayer
 * Created by Nathen
 * On 2016/04/10 15:45
 */
public abstract class VideoPlayerUtils extends FrameLayout implements View.OnClickListener, View.OnTouchListener, SeekBar.OnSeekBarChangeListener, SurfaceHolder.Callback, MediaManagerUtils.MediaPlayerListener {
    public static final String TAG = "INFO";
    public int CURRENT_STATE = -1;//-1相当于null
    public static final int CURRENT_STATE_PREPAREING = 0;
    public static final int CURRENT_STATE_PAUSE = 1;
    public static final int CURRENT_STATE_PLAYING = 2;
    public static final int CURRENT_STATE_OVER = 3;
    public static final int CURRENT_STATE_NORMAL = 4;
    public static final int CURRENT_STATE_ERROR = 5;
    protected boolean touchingProgressBar = false;
    public boolean IF_CURRENT_IS_FULLSCREEN = false;
    public boolean IF_FULLSCREEN_IS_DIRECTLY = false;//IF_CURRENT_IS_FULLSCREEN should be true first
    protected static boolean IF_FULLSCREEN_FROM_NORMAL = false;//to prevent infinite loop
    public static boolean IF_RELEASE_WHEN_ON_PAUSE = true;
    protected static long CLICK_QUIT_FULLSCREEN_TIME = 0;
    public static final int FULL_SCREEN_NORMAL_DELAY = 1000;

    public ImageView ivStart;
    public SeekBar skProgress;
    public ImageView ivFullScreen;
    public TextView tvTimeCurrent, tvTimeTotal;
    public ViewGroup rlSurfaceContainer;
    public ViewGroup llTopContainer, llBottomControl;
    public ResizeSurfaceView surfaceView;
    public SurfaceHolder surfaceHolder;
    public ImageView ivPlay;

    public String url;
    public Object[] objects;
    public Map<String, String> mapHeadData = new HashMap<>();

    public static Timer mUpdateProgressTimer;
    protected static BuriedPoint BURIED_POINT;
    protected int screenWidth;
    protected int screenHeight;
    protected AudioManager mAudioManager;

    protected int threshold = 80;
    protected float downX;
    protected float downY;
    protected boolean changeVolume = false;
    protected boolean changePosition = false;
    protected int downPosition;
    protected int downVolume;

    public Dialog dlgProgress;
    public ProgressBar dlgProgressProgressBar;
    public TextView dlgProgressCurrent;
    public TextView dlgProgressTotal;
    public ImageView dlgProgressIcon;
    protected int resultTimePosition;//change postion when finger up

    public Dialog dlgVolume;
    public ProgressBar dlgVolumeProgressBar;

    public VideoPlayerUtils(Context context) {
        super(context);
        init(context);
    }

    public VideoPlayerUtils(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    protected void init(Context context) {
        View.inflate(context, getLayoutId(), this);
        ivStart = (ImageView) findViewById(R.id.start);
        ivFullScreen = (ImageView) findViewById(R.id.fullscreen);
        skProgress = (SeekBar) findViewById(R.id.progress);
        tvTimeCurrent = (TextView) findViewById(R.id.current);
        tvTimeTotal = (TextView) findViewById(R.id.total);
        llBottomControl = (ViewGroup) findViewById(R.id.layout_bottom);
        rlSurfaceContainer = (RelativeLayout) findViewById(R.id.surface_container);
        llTopContainer = (ViewGroup) findViewById(R.id.layout_top);
        ivPlay = (ImageView) findViewById(R.id.ivPlay);

        ivStart.setOnClickListener(this);
        ivPlay.setOnClickListener(this);
        ivFullScreen.setOnClickListener(this);
        skProgress.setOnSeekBarChangeListener(this);
        llBottomControl.setOnClickListener(this);
        rlSurfaceContainer.setOnClickListener(this);
        skProgress.setOnTouchListener(this);

        rlSurfaceContainer.setOnTouchListener(this);
        screenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
        screenHeight = getContext().getResources().getDisplayMetrics().heightPixels;
        mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
    }

    public abstract int getLayoutId();

    protected static void setBuriedPoint(BuriedPoint buriedPoint) {
        BURIED_POINT = buriedPoint;
    }

    public boolean setUp(String url, Object... objects) {
        if (MediaManagerUtils.instance().listener == this && (System.currentTimeMillis() - CLICK_QUIT_FULLSCREEN_TIME) < FULL_SCREEN_NORMAL_DELAY)
            return false;
        CURRENT_STATE = CURRENT_STATE_NORMAL;
        this.url = url;
        this.objects = objects;
        setStateAndUi(CURRENT_STATE_NORMAL);
        return true;
    }

    public boolean setUp(String url, Map<String, String> mapHeadData, Object... objects) {
        if (setUp(url, objects)) {
            this.mapHeadData.clear();
            this.mapHeadData.putAll(mapHeadData);
            return true;
        }
        return false;
    }

    //set ui
    protected void setStateAndUi(int state) {
        CURRENT_STATE = state;
        switch (CURRENT_STATE) {
            case CURRENT_STATE_NORMAL:
                if (MediaManagerUtils.instance().listener == this) {
                    MediaManagerUtils.instance().mediaPlayer.release();
                }
                break;
            case CURRENT_STATE_PREPAREING:
                break;
            case CURRENT_STATE_PLAYING:
                startProgressTimer();
                break;
            case CURRENT_STATE_PAUSE:
                startProgressTimer();
                break;
            case CURRENT_STATE_ERROR:
                MediaManagerUtils.instance().mediaPlayer.release();
                break;
        }
    }

    @Override
    public void onClick(View v) {
        int i = v.getId();
        if (i == R.id.start || i == R.id.ivPlay) {
            if (TextUtils.isEmpty(url)) {
                Toast.makeText(getContext(), "No url", Toast.LENGTH_SHORT).show();
                return;
            }
            if (CURRENT_STATE == CURRENT_STATE_NORMAL || CURRENT_STATE == CURRENT_STATE_ERROR) {
                if (BURIED_POINT != null && CURRENT_STATE == CURRENT_STATE_NORMAL) {
                    BURIED_POINT.onClickStartIcon(url, objects);
                } else if (BURIED_POINT != null) {
                    BURIED_POINT.onClickStartError(url, objects);
                }
                prepareVideo();
            } else if (CURRENT_STATE == CURRENT_STATE_PLAYING) {
                MediaManagerUtils.instance().mediaPlayer.pause();
                setStateAndUi(CURRENT_STATE_PAUSE);
                if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
                    if (IF_CURRENT_IS_FULLSCREEN) {
                        BURIED_POINT.onClickStopFullscreen(url, objects);
                    } else {
                        BURIED_POINT.onClickStop(url, objects);
                    }
                }
            } else if (CURRENT_STATE == CURRENT_STATE_PAUSE) {
                if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
                    if (IF_CURRENT_IS_FULLSCREEN) {
                        BURIED_POINT.onClickResumeFullscreen(url, objects);
                    } else {
                        BURIED_POINT.onClickResume(url, objects);
                    }
                }
                MediaManagerUtils.instance().mediaPlayer.start();
                setStateAndUi(CURRENT_STATE_PLAYING);
            }
        } else if (i == R.id.fullscreen) {
            if (IF_CURRENT_IS_FULLSCREEN) {
                //quit fullscreen
                backFullscreen();
            } else {
                if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
                    BURIED_POINT.onEnterFullscreen(url, objects);
                }
                //to fullscreen
                MediaManagerUtils.instance().mediaPlayer.setDisplay(null);
                MediaManagerUtils.instance().lastListener = this;
                MediaManagerUtils.instance().listener = null;
                IF_FULLSCREEN_FROM_NORMAL = true;
                IF_RELEASE_WHEN_ON_PAUSE = false;
                FullScreenActivity.toActivityFromNormal(getContext(), CURRENT_STATE, url, VideoPlayerUtils.this.getClass(), this.objects);
            }
        } else if (i == R.id.surface_container && CURRENT_STATE == CURRENT_STATE_ERROR) {
            if (BURIED_POINT != null) {
                BURIED_POINT.onClickStartError(url, objects);
            }
            prepareVideo();
        }
    }

    protected void prepareVideo() {
        if (MediaManagerUtils.instance().listener != null) {
            MediaManagerUtils.instance().listener.onCompletion();
        }
        MediaManagerUtils.instance().listener = this;
        addSurfaceView();
        MediaManagerUtils.instance().prepareToPlay(getContext(), url, mapHeadData);
        setStateAndUi(CURRENT_STATE_PREPAREING);
    }

    public void addSurfaceView() {
        if (rlSurfaceContainer.getChildCount() > 0) {
            rlSurfaceContainer.removeAllViews();
        }
        surfaceView = new ResizeSurfaceView(getContext());
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);

        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        rlSurfaceContainer.addView(surfaceView, layoutParams);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        int id = v.getId();
        if (id == R.id.surface_container) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    touchingProgressBar = true;

                    downX = x;
                    downY = y;
                    changeVolume = false;
                    changePosition = false;
                    /////////////////////
                    cancelProgressTimer();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float deltaX = x - downX;
                    float deltaY = y - downY;
                    float absDeltaX = Math.abs(deltaX);
                    float absDeltaY = Math.abs(deltaY);
                    if (IF_CURRENT_IS_FULLSCREEN) {
                        if (!changePosition && !changeVolume) {
                            if (absDeltaX > threshold || absDeltaY > threshold) {
                                if (absDeltaX >= threshold) {
                                    changePosition = true;
                                    downPosition = getCurrentPositionWhenPlaying();
                                    if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
                                        BURIED_POINT.onTouchScreenSeekPosition(url, objects);
                                    }
                                } else {
                                    changeVolume = true;
                                    downVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
                                    if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
                                        BURIED_POINT.onTouchScreenSeekVolume(url, objects);
                                    }
                                }
                            }
                        }
                    }
                    if (changePosition) {
                        showProgressDialog(deltaX);
                    }
                    if (changeVolume) {
                        showVolumDialog(-deltaY);
                    }

                    break;
                case MotionEvent.ACTION_UP:
                    touchingProgressBar = false;
                    if (dlgProgress != null) {
                        dlgProgress.dismiss();
                    }
                    if (dlgVolume != null) {
                        dlgVolume.dismiss();
                    }
                    if (changePosition) {
                        MediaManagerUtils.instance().mediaPlayer.seekTo(resultTimePosition);
                        int duration = MediaManagerUtils.instance().mediaPlayer.getDuration();
                        int progress = resultTimePosition * 100 / (duration == 0 ? 1 : duration);
                        skProgress.setProgress(progress);
                    }
                    /////////////////////
                    startProgressTimer();
                    if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
                        if (IF_CURRENT_IS_FULLSCREEN) {
                            BURIED_POINT.onClickSeekbarFullscreen(url, objects);
                        } else {
                            BURIED_POINT.onClickSeekbar(url, objects);
                        }
                    }
                    break;
            }
        } else if (id == R.id.progress) {//if I am seeking bar,no mater whoever can not intercept my event
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    cancelProgressTimer();
                    ViewParent vpdown = getParent();
                    while (vpdown != null) {
                        vpdown.requestDisallowInterceptTouchEvent(true);
                        vpdown = vpdown.getParent();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    startProgressTimer();
                    ViewParent vpup = getParent();
                    while (vpup != null) {
                        vpup.requestDisallowInterceptTouchEvent(false);
                        vpup = vpup.getParent();
                    }
                    break;
            }
        }

        return false;
    }

    private void showProgressDialog(float deltaX) {
        if (dlgProgress == null) {
            View localView = LayoutInflater.from(getContext()).inflate(R.layout.progress_dialog, null);
            dlgProgressProgressBar = ((ProgressBar) localView.findViewById(R.id.duration_progressbar));
            dlgProgressCurrent = ((TextView) localView.findViewById(R.id.tv_current));
            dlgProgressTotal = ((TextView) localView.findViewById(R.id.tv_duration));
            dlgProgressIcon = ((ImageView) localView.findViewById(R.id.duration_image_tip));
            dlgProgress = new Dialog(getContext(), R.style.style_dialog_progress);
            dlgProgress.setContentView(localView);
            dlgProgress.getWindow().addFlags(Window.FEATURE_ACTION_BAR);
            dlgProgress.getWindow().addFlags(32);
            dlgProgress.getWindow().addFlags(16);
            dlgProgress.getWindow().setLayout(-2, -2);
            WindowManager.LayoutParams localLayoutParams = dlgProgress.getWindow().getAttributes();
            localLayoutParams.gravity = 49;
            localLayoutParams.y = getResources().getDimensionPixelOffset(R.dimen.progress_dialog_margin_top);
            dlgProgress.getWindow().setAttributes(localLayoutParams);
        }
        if (!dlgProgress.isShowing()) {
            dlgProgress.show();
        }
        int totalTime = MediaManagerUtils.instance().mediaPlayer.getDuration();
        resultTimePosition = (int) (downPosition + deltaX * totalTime / screenWidth);
        dlgProgressCurrent.setText(TimeUtils.stringForTime(resultTimePosition));
        dlgProgressTotal.setText(" / " + TimeUtils.stringForTime(totalTime) + "");
        dlgProgressProgressBar.setProgress(resultTimePosition * 100 / totalTime);
        if (deltaX > 0) {
            dlgProgressIcon.setBackgroundResource(R.mipmap.forward_icon);
        } else {
            dlgProgressIcon.setBackgroundResource(R.mipmap.backward_icon);
        }
    }

    private void showVolumDialog(float deltaY) {
        if (dlgVolume == null) {
            View localView = LayoutInflater.from(getContext()).inflate(R.layout.volume_dialog, null);
            dlgVolumeProgressBar = ((ProgressBar) localView.findViewById(R.id.volume_progressbar));
            dlgVolume = new Dialog(getContext(), R.style.style_dialog_progress);
            dlgVolume.setContentView(localView);
            dlgVolume.getWindow().addFlags(8);
            dlgVolume.getWindow().addFlags(32);
            dlgVolume.getWindow().addFlags(16);
            dlgVolume.getWindow().setLayout(-2, -2);
            WindowManager.LayoutParams localLayoutParams = dlgVolume.getWindow().getAttributes();
            localLayoutParams.gravity = 19;
            localLayoutParams.x = getContext().getResources().getDimensionPixelOffset(R.dimen.volume_dialog_margin_left);
            dlgVolume.getWindow().setAttributes(localLayoutParams);
        }
        if (!dlgVolume.isShowing()) {
            dlgVolume.show();
        }
        int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        int deltaV = (int) (max * deltaY * 3 / screenHeight);
        mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, downVolume + deltaV, 0);
        int transformatVolume = (int) (downVolume * 100 / max + deltaY * 3 * 100 / screenHeight);
        dlgVolumeProgressBar.setProgress(transformatVolume);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (fromUser) {
            int time = progress * MediaManagerUtils.instance().mediaPlayer.getDuration() / 100;
            MediaManagerUtils.instance().mediaPlayer.seekTo(time);
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        setDisplayCaseFailed();
    }


    private void setDisplayCaseFailed() {//这里如果一直不成功是否有隐患
        try {
            MediaManagerUtils.instance().mediaPlayer.setDisplay(surfaceHolder);
        } catch (IllegalArgumentException e) {
            Log.i(TAG, "recreate surfaceview from IllegalArgumentException");
            addSurfaceView();
            e.printStackTrace();
        } catch (IllegalStateException e1) {
            Log.i(TAG, "recreate surfaceview from IllegalStateException");
            addSurfaceView();
            e1.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }


    @Override
    public void onPrepared() {
        if (CURRENT_STATE != CURRENT_STATE_PREPAREING) return;
        MediaManagerUtils.instance().mediaPlayer.start();
        startProgressTimer();
        setStateAndUi(CURRENT_STATE_PLAYING);
    }

    @Override
    public void onAutoCompletion() {
        //make me normal first
        if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
            if (IF_CURRENT_IS_FULLSCREEN) {
                BURIED_POINT.onAutoCompleteFullscreen(url, objects);
            } else {
                BURIED_POINT.onAutoComplete(url, objects);
            }
        }
        onCompletion();
    }

    @Override
    public void onCompletion() {
        //make me normal first
        cancelProgressTimer();
        resetProgressAndTime();
        setStateAndUi(CURRENT_STATE_NORMAL);
        if (rlSurfaceContainer.getChildCount() > 0) {
            rlSurfaceContainer.removeAllViews();
        }
        //if fullscreen finish activity what ever the activity is directly or click fullscreen
        finishMyFullscreen();

        if (IF_FULLSCREEN_FROM_NORMAL) {//如果在进入全屏后播放完就初始化自己非全屏的控件
            IF_FULLSCREEN_FROM_NORMAL = false;
            MediaManagerUtils.instance().lastListener.onCompletion();
        }
    }

    @Override
    public void onBufferingUpdate(int percent) {
        if (CURRENT_STATE != CURRENT_STATE_NORMAL && CURRENT_STATE != CURRENT_STATE_PREPAREING) {
            setTextAndProgress(percent);
        }
    }

    @Override
    public void onSeekComplete() {

    }

    @Override
    public void onError(int what, int extra) {
        if (what != 38 && what != -38) {
            setStateAndUi(CURRENT_STATE_ERROR);
        }
    }

    @Override
    public void onVideoSizeChanged() {
        int mVideoWidth = MediaManagerUtils.instance().currentVideoWidth;
        int mVideoHeight = MediaManagerUtils.instance().currentVideoHeight;
        if (mVideoWidth != 0 && mVideoHeight != 0) {
            surfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
            surfaceView.requestLayout();
        }
    }

    @Override
    public void onBackFullscreen() {
        CURRENT_STATE = MediaManagerUtils.instance().lastState;
        setStateAndUi(CURRENT_STATE);
    }

    protected void startProgressTimer() {
        cancelProgressTimer();
        mUpdateProgressTimer = new Timer();
        mUpdateProgressTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (getContext() != null && getContext() instanceof Activity) {
                    ((Activity) getContext()).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (CURRENT_STATE == CURRENT_STATE_PLAYING || CURRENT_STATE == CURRENT_STATE_PAUSE) {
                                setTextAndProgress(0);
                            }
                        }
                    });
                }
            }
        }, 0, 300);
    }

    protected void cancelProgressTimer() {
        if (mUpdateProgressTimer != null) {
            mUpdateProgressTimer.cancel();
        }
    }

    protected int getCurrentPositionWhenPlaying() {
        int position = 0;
        if (CURRENT_STATE == CURRENT_STATE_PLAYING || CURRENT_STATE == CURRENT_STATE_PAUSE) {
            position = MediaManagerUtils.instance().mediaPlayer.getCurrentPosition();
        }
        return position;
    }

    protected void setTextAndProgress(int secProgress) {
        int position = getCurrentPositionWhenPlaying();
        int duration = MediaManagerUtils.instance().mediaPlayer.getDuration();
        // if duration == 0 (e.g. in HLS streams) avoids ArithmeticException
        int progress = position * 100 / (duration == 0 ? 1 : duration);
        setProgressAndTime(progress, secProgress, position, duration);
    }

    protected void setProgressAndTime(int progress, int secProgress, int currentTime, int totalTime) {
        if (!touchingProgressBar) {
            if (progress != 0) skProgress.setProgress(progress);
        }
        if (secProgress != 0) skProgress.setSecondaryProgress(secProgress);
        tvTimeCurrent.setText(TimeUtils.stringForTime(currentTime));
        tvTimeTotal.setText(TimeUtils.stringForTime(totalTime));
    }

    protected void resetProgressAndTime() {
        skProgress.setProgress(0);
        skProgress.setSecondaryProgress(0);
        tvTimeCurrent.setText(TimeUtils.stringForTime(0));
        tvTimeTotal.setText(TimeUtils.stringForTime(0));
    }

    protected void quitFullScreenGoToNormal() {
        if (BURIED_POINT != null && MediaManagerUtils.instance().listener == this) {
            BURIED_POINT.onQuitFullscreen(url, objects);
        }
        MediaManagerUtils.instance().mediaPlayer.setDisplay(null);
        MediaManagerUtils.instance().listener = MediaManagerUtils.instance().lastListener;
        MediaManagerUtils.instance().lastState = CURRENT_STATE;//save state
        MediaManagerUtils.instance().listener.onBackFullscreen();
        finishMyFullscreen();
    }

    protected void finishMyFullscreen() {
        if (getContext() instanceof FullScreenActivity) {
            ((FullScreenActivity) getContext()).finish();
        }
    }

    public void backFullscreen() {
        if (IF_FULLSCREEN_IS_DIRECTLY) {
            MediaManagerUtils.instance().mediaPlayer.stop();
            finishMyFullscreen();
        } else {
            CLICK_QUIT_FULLSCREEN_TIME = System.currentTimeMillis();
            IF_RELEASE_WHEN_ON_PAUSE = false;
            quitFullScreenGoToNormal();
        }
    }

    public static void releaseAllVideos() {
        if (IF_RELEASE_WHEN_ON_PAUSE) {
            MediaManagerUtils.instance().mediaPlayer.release();
            if (MediaManagerUtils.instance().listener != null) {
                MediaManagerUtils.instance().listener.onCompletion();
            }
        } else {
            IF_RELEASE_WHEN_ON_PAUSE = true;
        }
    }

    /**
     * if I am playing release me
     */
    public void release() {
        if (CURRENT_STATE != CURRENT_STATE_NORMAL) {
            releaseAllVideos();
        }
    }
}
